/**
 * ex3.数组与切片与map
 *
 * @author cyy
 * @date 2020/10/28
 */
package main

import (
	"fmt"
	"sort"
)

func main() {

	/*
		数组
			定义
				①	var arr1 [3]int
				②	var arr2 = [3]int{1, 2, 3}
					arr3 := [3]int{1, 2, 3}
				③	编译器自行推断数组的长度（多维数组只有第一层能够自行推断
					var arr4 = [...]int{1, 2, 3}
					arr5 := [...]int{1, 2, 3}
				④	指定索引值进行初始化
					arr6 := [...]int{0:1, 2:3}
	*/
	fmt.Println("============================ 数组 ============================")

	/*
		数组的遍历
			使用len(arr)或range
	*/
	fmt.Println("\n---------------------------- 数组的遍历 ----------------------------")
	arr := []string{"c++", "java", "golang"}
	// 通过索引
	for i := range arr {
		fmt.Printf(arr[i] + " ")
	}
	fmt.Println()
	// foreach
	for _, s := range arr {
		fmt.Printf(s + " ")
	}
	fmt.Println()

	/*
		Slice - 切片
			一个拥有相同类型元素的可变长度的序列，非常灵活，支持自动扩容，内部结构包括地址、长度和容量
			定义（未定义的切片为nil（相当于java中的null）

			切片的本质就是对底层数组的封装，包含了 底层数组的指针、切片的长度、切片的容量 三个信息
	*/
	fmt.Println("\n============================ 切片 ============================")

	/*
		切片的定义与初始化
	*/
	fmt.Println("\n---------------------------- 切片的定义 ----------------------------")
	// 基于数组（/切片）定义切片 —— [l:r]
	//	基于数组
	arr0 := [...]int{0, 1, 2, 3}
	var slice0 []int = arr0[1:]
	fmt.Println(slice0)
	//	基于切片
	slices := []int{0, 1, 2, 3, 4, 5}
	slice1 := slices[:] // len = 6，cap = 6
	fmt.Println(slice1)

	// 使用 make([]T, size, cap) 定义
	sliceA := make([]int, 2, 3)
	sliceA[1] = 1
	// sliceA[2] = 1 => 超出长度时报错：panic: runtime error: index out of range [1] with length 1
	fmt.Println(sliceA)

	/*
		切片的长度与容量
	*/
	fmt.Println("\n---------------------------- len与cap ----------------------------")
	// 使用len()获取切片的长度，使用cap()获取切片的容量（容量是从第一个元素算起到最后一个元素的总数）
	fmt.Printf("slice1 —— len = %d，cap = %d\n", len(slice1), cap(slice1))
	slice2 := slices[1:] // len = 5，cap = 5
	fmt.Printf("slice2 —— len = %d，cap = %d\n", len(slice2), cap(slice2))
	slice3 := slices[1:3] // len = 2，cap = 5
	fmt.Printf("slice3 —— len = %d，cap = %d\n", len(slice3), cap(slice3))

	/*
		切片的基本操作
	*/
	fmt.Println("\n---------------------------- append() ----------------------------")
	// 使用append()扩容添加新元素
	fmt.Printf("添加前：sliceA = %v，len = %d，cap = %d\n", sliceA, len(sliceA), cap(sliceA))
	sliceA = append(sliceA, 2, 3)
	fmt.Printf("添加后：sliceA = %v，len = %d，cap = %d\n", sliceA, len(sliceA), cap(sliceA))
	// 使用append()合并切片
	sliceB := []int{4, 5}
	sliceA = append(sliceA, sliceB...)
	fmt.Printf("合并后：sliceA = %v，len = %d，cap = %d\n", sliceA, len(sliceA), cap(sliceA))
	// 使用append()删除元素
	// 	go中没有删除切片元素的专用方法，但是可以使用切片本身的特性来删除元素
	sliceA = append(sliceA[:1], sliceA[2:]...)
	fmt.Printf("删除后：sliceA = %v，len = %d，cap = %d\n", sliceA, len(sliceA), cap(sliceA))

	fmt.Println("\n---------------------------- copy() ----------------------------")
	// copy()复制切片，长度不够时就只复制部分元素
	sliceC := make([]int, 4, 5)
	copy(sliceC, sliceA)
	fmt.Printf("sliceC = %v，len = %d，cap = %d\n", sliceC, len(sliceC), cap(sliceC))

	/*
		☆sort包
	*/
	fmt.Println("\n---------------------------- sort() ----------------------------")
	array := []int{9, 5, 8, 7, 1, 2, 3, 6, 4, 0}
	fmt.Printf("排序前：%v\n", array)
	sort.Ints(array) // 等同于 sort.Sort(sort.IntSlice(array))
	fmt.Printf("正序排序：%v\n", array)
	sort.Sort(sort.Reverse(sort.IntSlice(array)))
	fmt.Printf("逆序排序：%v\n", array)
	// 自定义排序实现逆序排序
	sort.Slice(array, func(i, j int) bool {
		return array[i] < array[j]
	})
	fmt.Printf("逆序后的逆序排序：%v\n", array)

	fmt.Println("\n============================ map ============================")
	/*
		初始化
	*/
	fmt.Println("\n---------------------------- 初始化 ----------------------------")
	// 通过make()函数初始化
	mapA := make(map[int]int)
	mapA[0] = 1
	mapA[2] = 3
	fmt.Println("mapA:", mapA)

	// 声明时填充数据
	// 	注意：最后的“,”必须要加
	mapB := map[int]int{
		1: 1, 2: 2, 3: 3,
	}
	fmt.Println("mapB:", mapB)

	// 定义v为切片的map
	mapC := make(map[int][]int)
	mapC[0] = []int{1, 2, 3}
	fmt.Println(mapC)

	/*
		value的获取
	*/
	//		若无，第二个参数返回false
	fmt.Println("\n---------------------------- 获取value ----------------------------")
	val, ok := mapB[0]
	fmt.Printf("value: %v, ok: %v\n", val, ok)

	/*
		kv的删除
	*/
	fmt.Println("\n---------------------------- 删除kv ----------------------------")
	delete(mapB, 3)
	fmt.Println(mapB)

	/*
		map的遍历
	*/
	fmt.Println("\n---------------------------- map的遍历 ----------------------------")
	for k := range mapA {
		fmt.Println(k)
	}
	for k, v := range mapA {
		fmt.Printf("key = %v, val = %v\n", k, v)
	}
}
